package netty.CustomizeTheMessageProtocol;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * @author Kagome
 * @title: SelfDefineEncodeHandler
 * @projectName boot2.X-netty
 * @description: 拆包
 * @date 2019/6/4 13:24
 */
public class SelfDefineEncodeHandler extends ByteToMessageDecoder {
    private static int count = 0;
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf bufferIn, List<Object> out) throws Exception {
        System.out.println("decode call count="+ ++count);
        System.out.println("bufferIn.readableBytes()="+bufferIn.readableBytes());
        System.out.println("什么鬼");
        //如果接收到的字节还不到4个字节,也即是连消息长度字段中的内容都不完整的,直接return。
        if (bufferIn.readableBytes() < 4) {
            return;
        }
        //对于拆包这种场景,由于还未读取到完整的消息,bufferIn.readableBytes() 会小于length,
        // 并重置bufferIn的readerIndex为0,然后退出,ByteToMessageDecoder会乖乖的等待下个包的到来。
        //由于第一次调用中readerIndex被重置为0,那么decode方法被调用第二次的时候,beginIndex还是为0的。
        int beginIndex = bufferIn.readerIndex();
        //是读取4个字节作为长度，这个解析4个字节为数字，注意字节从高位开始还是低位开始
        // long batch = ((byteBuf.getByte(7) & 0xFF) << 24)
        // ((byteBuf.getByte(6) & 0xFF) << 16) [表情] ((byteBuf.getByte(5) & 0xFF) << 8)
        // (byteBuf.getByte(4) & 0xFF);
        int length = bufferIn.readInt();

        if (bufferIn.readableBytes() < length) {
            bufferIn.readerIndex(beginIndex);
            return;
        }
        //将readerIndex设置为最大。首先代码能执行到这里,针对拆包这种场景而言,
        // 已经是读取到一条有效完整的消息了。这个时候需要通知ByteToMessageDecoder类,
        // bufferIn中的数据已经读取完毕了,不要再调用decode方法了。
        // ByteToMessageDecoder类的底层会根据bufferIn.isReadable()方法来判断是否读取完毕。
        // 只有将readerIndex设置为最大,bufferIn.isReadable()方法才会返回false
        bufferIn.readerIndex(beginIndex + 4 + length);

        //当decode方法执行完后,会释放bufferIn这个缓冲区,如果将执行完释放操作的bufferIn传递给下个处理器的话,
        // 一旦下个处理器调用bufferIn的读或者写的方法时,会立刻报出IllegalReferenceCountException异常的。
        ByteBuf otherByteBufRef = bufferIn.slice(beginIndex, 4 + length);

        otherByteBufRef.retain();

        out.add(otherByteBufRef);

        System.out.println("beginIndex="+beginIndex);
        System.out.println("end==============================================");
    }
}
